package com.automapper.execute.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.automapper.constants.ParameterConstants;
import com.automapper.execute.Execute;
import com.automapper.sqlbuilder.SqlBuilderTemplate;
import com.automapper.utils.ObjectFacade;
import com.automapper.utils.ParameterUtils;
import com.automapper.utils.PropertiesFacade;
import com.automapper.utils.SqlSourceBuilderUtils;

public class PersistentExecute implements Execute {

	private static final Logger logger = LoggerFactory.getLogger(PersistentExecute.class);
	
	private SqlBuilderTemplate sqlBuilder;
	
	@Override
	public void process(MetaObject metaStatementHandler, Invocation invocation, PropertiesFacade propertiesFacade) throws Exception {
		String key = "list";
		MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
		
		//获取入库数据
		Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
		Map<String, Object> parameterMap = (Map<String, Object>) parameterObject;
	
		List<Object> list = ParameterUtils.getParameterList(parameterMap);
		/*
		 *  新增key=list的参数
		 *  在mybatis 3.3.1版之后，批量回写对象ID，判断参数有没有key=list的值
		 */
		parameterMap.put(key, list);
		
		ObjectFacade objectFacade = new ObjectFacade(list.get(0));
		//过滤主键，主键的值不能入库。如果主键的值入库会导致数据库（mysql）无法生成新的值，出现锁表
		this.setIdExculde(parameterMap, objectFacade);
		
		MetaObject metaMappedStatement = SystemMetaObject.forObject(mappedStatement);
		//keyProperties赋值，keyProperties主要作用是将数据库生成的主键赋值到对象指定的属性
		metaMappedStatement.setValue("keyProperties", new String[]{/*key + "." +*/ objectFacade.getPrimaryKeyField().getFieldName()});
		
		Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
		
		propertiesFacade.setKey(key);
		String newSql = sqlBuilder.buildSql(parameterObject, propertiesFacade);
		logger.debug("Auto generated sql:" + newSql);
		
		SqlSource sqlSource = SqlSourceBuilderUtils.buildSqlSource(configuration, newSql, parameterObject.getClass());
		List<ParameterMapping> parameterMappings = sqlSource.getBoundSql(parameterObject).getParameterMappings();
		metaStatementHandler.setValue("delegate.boundSql.sql", sqlSource.getBoundSql(parameterObject).getSql());
		metaStatementHandler.setValue("delegate.boundSql.parameterMappings", parameterMappings);
		/*
		 *  防止同一事物内，先执行persistent方法再执行insert方法，导致后面insert方法出错。
		 *  因为不设置为空，会将改值带到执行insert方法的逻辑内。
		 *  这样就会修改insert方法@Param的value值，导致无法mybatis无法获取参数
		 */
		propertiesFacade.setKey(null);
	}
	
	/**
	 * 在过滤字段集合里添加主键过滤
	 */
	private void setIdExculde(Map<String, Object> parameterMap, ObjectFacade objectFacade) {
		List<String> exculde = new ArrayList<>();
		if (parameterMap.containsKey(ParameterConstants.EXCLUDE_COLUMN)) {
			Object object = parameterMap.get(ParameterConstants.EXCLUDE_COLUMN);
			exculde.addAll((List<String>) object);
		}
		exculde.add(objectFacade.getPrimaryKeyColumnName());
		parameterMap.put(ParameterConstants.EXCLUDE_COLUMN, exculde);
	}
}
